/*

    This file is part of Hometree.

    Hometree is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Hometree is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Hometree.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2011,2012 Roman Held

*/


/********************************************************************\
                            Includes
\********************************************************************/
#include <QDebug>
#include "htr/htrglobal.h"
#include "htr/htrresource.h"
#include "htr/htrclient.h"
#include "htr/htrmimedataresource.h"
#include "htr/htrmimedataadapter.h"
#include "htr/htrlog.h"

/********************************************************************\
                           Constants
\********************************************************************/
#define IDENT "MDR"

/********************************************************************\
                         Implementation
\********************************************************************/
/*--------------------------------------------------------------------
*/
HtrMimeDataResource::HtrMimeDataResource(QObject *parent)
 : HtrResource(Htr::MimeDataType, parent)
{
}

/*--------------------------------------------------------------------
*/
HtrMimeDataResource::~HtrMimeDataResource()
{
}

/*--------------------------------------------------------------------
*/
bool  HtrMimeDataResource::open(Htr::Res::OpenMode mode)
{
  mOpenMode = mode;

  /*
      Falls "open" nach "state-identified" erfolgt..
      TODO: saubere loesung...?
  */
  if (mOpenMode > 0 && state() == Htr::Res::StIdentified) {
    stateIdentified();
  }
}

/*--------------------------------------------------------------------
*/
void  HtrMimeDataResource::close()
{
  if (state() != Htr::Res::StReady)
    return;

  // TODO: was waehrend Init..?!?
  sendClose();

  setState(Htr::Res::StOffline);
}

/*--------------------------------------------------------------------
*/
void  HtrMimeDataResource::setMimeType(const QString &mimeType)
{
  mMimeType = mimeType;

  if (state() == Htr::Res::StReady)
    sendMimeType();
}

/*--------------------------------------------------------------------
*/
QString HtrMimeDataResource::mimeType() const
{
  return mMimeType;
}

/*--------------------------------------------------------------------
*/
void  HtrMimeDataResource::setMimeData(const QByteArray &data)
{
  Q_ASSERT(client());
  mMimeData = data;
  
  if (state() == Htr::Res::StReady)
    sendMimeData();
}

/*--------------------------------------------------------------------
*/
QByteArray HtrMimeDataResource::mimeData() const
{
  return mMimeData;
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::installAdapter(HtrMimeDataAdapter *adapter)
{ 
  Q_ASSERT(adapter);
  adapter->init(&mMimeData, mMimeType);
  connect(adapter, SIGNAL(destroyed(QObject*)),
          this, SLOT(childDestroyed(QObject*)));
  mAdapters << adapter;
  if (!adapter->parent())  // Memoryleaks bei falscher Anwendung verhindern
    adapter->setParent(this);
}

/*--------------------------------------------------------------------
*/
bool HtrMimeDataResource::handleMsg(qint32 msgId, QDataStream &inStream)
{
  if (HtrResource::handleMsg(msgId,inStream))
    return true;

  bool ret = true;
  switch(msgId) {
    case Htr::Net::UpdateMsg: { 
      inStream >> mMimeType;
      inStream >> mMimeData;
      foreach(QObject *obj, mAdapters) {
        HtrMimeDataAdapter *a = dynamic_cast<HtrMimeDataAdapter*>(obj);
        Q_ASSERT(a);
        a->init(&mMimeData,mMimeType);
      }
      if (state() == Htr::Res::StIdentified)
        setState(Htr::Res::StReady);
      emit readyRead();
    } break;
    case Htr::Net::MimeDataMsg: { 
      inStream >> mMimeData;
      emit readyRead();
    } break;
    case Htr::Net::MimeTypeMsg: { 
      inStream >> mMimeType;
      foreach(QObject *obj, mAdapters) {
        HtrMimeDataAdapter *a = dynamic_cast<HtrMimeDataAdapter*>(obj);
        Q_ASSERT(a);
        a->init(&mMimeData,mMimeType);
      }
      emit readyRead();
    } break;
    case Htr::Net::ErrorMsg: { 
        setState(Htr::Res::StError);
        // TODO: Behandlung des Error-Codes?
        qint32 errCode;
        inStream >> errCode; 
    } break;
    default :  {
      qWarning() << "UNHANDLED MESSAGE: " << msgId;
      ret = false;
    }
  }
  return ret; 
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::handleStateChange()
{
  HtrResource::handleStateChange();

  switch (state()) {
    case Htr::Res::StOffline:
    case Htr::Res::StUndefined:
      break;
    case Htr::Res::StInit: stateInit(); break;
    case Htr::Res::StIdentified: stateIdentified(); break;
    case Htr::Res::StReady: stateReady(); break;
    case Htr::Res::StError: stateError(); break;
  }
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::handleCreating()
{
  HtrResource::handleCreating();

  /*
    Wenn ICH die Resource erstellt habe, sollte ich auch 
    die Initialen Werte liefern...
  */ 
  if ( (mOpenMode & Htr::Res::WriteOnly) == Htr::Res::WriteOnly) {
    sendMimeType();
    sendMimeData();
  }
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::clientStateChanged()
{
  Q_ASSERT(client());
  if (client()->isReady()) {
    setState(Htr::Res::StInit);
  }
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::stateInit()
{
  sendInit();
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::stateIdentified()
{
  if (mOpenMode > 0) {
    sendOpen();
  } else
    qWarning() << "HtrMimeDataResource::stateIdentified: kein Open-Mode";
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::stateReady()
{
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::stateError()
{
  qWarning() << "HtrMimeDataResource::stateError not implemented";
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::sendInit()
{
  Q_ASSERT(client());
  QDataStream &stream = client()->prepareStream(Htr::Net::ClIdentMsg);
  stream << url();
  stream << (qint32)type();
  client()->writeStream();
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::sendMimeType()
{
  Q_ASSERT(client());
  QDataStream &stream = client()->prepareStream();
  stream << id();
  stream << (qint32)Htr::Net::MimeTypeMsg;
  stream << mMimeType;
  client()->writeStream();
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::sendMimeData()
{
  Q_ASSERT(client());
  QDataStream &stream = client()->prepareStream();
  stream << id();
  stream << (qint32)Htr::Net::MimeDataMsg;
  stream << mMimeData;
  client()->writeStream();
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::sendOpen()
{
  Q_ASSERT(client());
  QDataStream &stream = client()->prepareStream();
  stream << id();
  stream << (qint32)Htr::Net::OpenMsg;
  stream << (qint32)mOpenMode;
  client()->writeStream();
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::sendClose()
{
  Q_ASSERT(client());
  QDataStream &stream = client()->prepareStream();
  stream << id();
  stream << (qint32)Htr::Net::CloseMsg;
  client()->writeStream();
}

/*--------------------------------------------------------------------
*/
void HtrMimeDataResource::childDestroyed(QObject *obj)
{
  if (mAdapters.contains(obj))
    mAdapters.removeAll(obj);
}
